iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
自我挑戰組

打掉重練!Django的還債之旅~系列 第 22

Day22. 今天來稍微看一下ORM的原始碼!

  • 分享至 

  • xImage
  •  

前言

昨天我們看到了ORM是怎麼使用的,那麼今天就稍微來看一下ORM實際是怎麼做的吧,走到哪看到哪~

正題

我們現在有的線索就只有ORM的用法~
https://ithelp.ithome.com.tw/upload/images/20231007/20162905IWodg17n7P.png
直接點進去呢,會跑到這裡~
https://ithelp.ithome.com.tw/upload/images/20231007/20162905sh8mp80urR.png
這邊是.pyi的檔案,讓vscode能夠知道該class類別有什麼function
那他實際是什麼類別呢,我們直接像上圖一樣print出來看看~
<class 'django.db.models.manager.Manager'>
再依照這個類別的位置下去看看!
https://ithelp.ithome.com.tw/upload/images/20231007/20162905P3BAiJtokw.png
我們這邊先回頭一下,去找找看這個Manager是怎麼被生出來的~
這邊就要回頭去看models.py裡面我們Todo的父類別models.Model
https://ithelp.ithome.com.tw/upload/images/20231007/20162905g5fgzAzTIf.png
這邊可以看到metaclass,這也是python中很特別的物件,我也沒有把握自己可以講好,就請大家去看看Dboy的文章吧!
然後python還有一個特別的magic method
https://ithelp.ithome.com.tw/upload/images/20231007/20162905OFDHoGRSiu.png
其實這個從字面上的意思也能看出來,當一個物件被new出來時會觸發的method,也就是說會在__init__之前被觸發~
之後呢直接ctrl+F找關鍵字objects
https://ithelp.ithome.com.tw/upload/images/20231007/20162905Cb5OssHmiC.png
這邊就會看到Manager的物件囉~
在接著看BaseManager.from_queryset()
https://ithelp.ithome.com.tw/upload/images/20231007/20162905FDYIitrGFC.png
這邊是python class的另一種寫法,Dboy也有說明!!
然後把queryset的function都塞到上面那個新的class裡面
https://ithelp.ithome.com.tw/upload/images/20231007/20162905z0vSzrhXFl.png
所以最後我們就能在QuerySet這個class裡面找到我們使用的function filter啦!!
https://ithelp.ithome.com.tw/upload/images/20231007/20162905asYzlNoI10.png
我試著再往裡面查看,但在裡面就看不太懂在寫什麼了QQ

但我弄著弄著發現一個有趣的點

def person_todolist(request, id):
    todo = Todo.objects.select_related("owner").filter(owner=id)
    return render(request, 'person_todolist.html', {"todo": todo})

def person_todolist(request, id):
    todo = Todo.objects.select_related("owner").filter(owner=id)
    print(todo)
    return render(request, 'person_todolist.html', {"todo": todo})

這兩個的差異可以透過我們的logging在console中看到
分別為
無print

(0.001) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2023-10-07 08:16:37.529260' AND "django_session"."session_key" = 'hyj5kk8n038t2ofx6owx45fzva85u36z') LIMIT 21; args=('2023-10-07 08:16:37.529260', 'hyj5kk8n038t2ofx6owx45fzva85u36z'); alias=default
(0.000) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 LIMIT 21; args=(1,); alias=default
(0.000) SELECT "todo_list"."id", "todo_list"."owner_id", "todo_list"."title", "todo_list"."complete", "todo_list"."add_date", "person"."id", "person"."name", "person"."sex" FROM "todo_list" INNER JOIN "person" ON ("todo_list"."owner_id" = "person"."id") WHERE "todo_list"."owner_id" = 1; args=(1,); alias=default

和有print

(0.001) SELECT "todo_list"."id", "todo_list"."owner_id", "todo_list"."title", "todo_list"."complete", "todo_list"."add_date", "person"."id", "person"."name", "person"."sex" FROM "todo_list" INNER JOIN "person" ON ("todo_list"."owner_id" = "person"."id") WHERE "todo_list"."owner_id" = 1 LIMIT 21; args=(1,); alias=default
<QuerySet [<Todo: Todo object (1)>, <Todo: Todo object (2)>, <Todo: Todo object (3)>]>
(0.000) SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > '2023-10-07 08:15:55.474015' AND "django_session"."session_key" = 'hyj5kk8n038t2ofx6owx45fzva85u36z') LIMIT 21; args=('2023-10-07 08:15:55.474015', 'hyj5kk8n038t2ofx6owx45fzva85u36z'); alias=default
(0.000) SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 LIMIT 21; args=(1,); alias=default
(0.000) SELECT "todo_list"."id", "todo_list"."owner_id", "todo_list"."title", "todo_list"."complete", "todo_list"."add_date", "person"."id", "person"."name", "person"."sex" FROM "todo_list" INNER JOIN "person" ON ("todo_list"."owner_id" = "person"."id") WHERE "todo_list"."owner_id" = 1; args=(1,); alias=default

我們可以從上面兩個logging的差異中看到,如果有print的話,django會先行去db下SQL,而沒有的話則是在render的時候才下SQL,看來明天的功課就是看看render裡面有什麼奧秘了!

結語

不得不說ORM這個框架真的是非常巨大,能力尚且不足完全無法想像這樣的架構是怎麼規劃和實作出來的!希望不久的將來自己也能手刻一套出來試試看!


上一篇
Day21. 看看djangoORM與其對應的SQL是否為預期的樣子!
下一篇
Day23. ORM觸發SQL的地方(這邊是print~)
系列文
打掉重練!Django的還債之旅~30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言